package demo.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class TimeClient {

    public static void main(String[] args) throws InterruptedException {
        int port = 8080;
        if (args != null && args.length > 0) {
            port = Integer.parseInt(args[0]);
        }
        new Thread(new TimeClientHandle("127.0.0.1", port)).start();
        Thread.currentThread().join();
    }

    public static class TimeClientHandle implements Runnable {
        private String host;
        private int port;
        private Selector selector;
        private SocketChannel socketChannel;
        private volatile boolean stop;

        public TimeClientHandle(String host, int port) {
            this.host = host == null ? "127.0.0.1" : host;
            this.port = port;

            try {
                selector = Selector.open();
                socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(false);
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }

        @Override
        public void run() {
            try {
                doConnect();
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }

            while (!stop) {
                try {
                    selector.select(1000);
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
                    SelectionKey key = null;
                    while (selectionKeyIterator.hasNext()) {
                        key = selectionKeyIterator.next();
                        selectionKeyIterator.remove();
                        try {
                            handleInput(key);
                        } catch (IOException e) {
                            e.printStackTrace();
                            key.cancel();
                            if (key.channel() != null) {
                                key.channel().close();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }

        /**
         * 创建连接
         * 1.如果直接连接成功，直接注册读事件到多路复用器上
         * 2.没有练就额成功的话，注册连接事件到多路复用器上
         * @throws IOException
         */
        private void doConnect() throws IOException {
            if (socketChannel.connect(new InetSocketAddress(host, port))) {
                socketChannel.register(selector, SelectionKey.OP_READ);
                doWrite(socketChannel);
            } else {
                socketChannel.register(selector, SelectionKey.OP_CONNECT);
            }
        }

        /**
         * 发送请求数据到管道中
         *
         *
         * @param socketChannel
         * @throws IOException
         */
        private void doWrite(SocketChannel socketChannel) throws IOException {
            byte[] bytes = "QUERY TIME ORDER".getBytes(StandardCharsets.UTF_8);
            ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
            byteBuffer.put(bytes);
            byteBuffer.flip();
            socketChannel.write(byteBuffer);
            if (!byteBuffer.hasRemaining()) {
                System.out.println("Send order 2 server succeed .");
            }
        }

        /**
         * 先判断key 是否是连接事件，如果连接成功，注册一个读时间发送查询请求
         *
         * @param selectionKey
         * @throws IOException
         */
        private void handleInput(SelectionKey selectionKey) throws IOException {
            if (selectionKey.isValid()) {
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                //判断是否连接成功
                if (selectionKey.isConnectable()) {
                    System.out.println("接收到服务器连接事件。。。。");
                    //完成连接后，注册一个读事件
                    if (socketChannel.finishConnect()) {
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        doWrite(socketChannel);
                    }
                }

                //读事件准备就绪
                if (selectionKey.isReadable()) {
                    System.out.println("接收到服务器读事件。。。。");
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int read = socketChannel.read(byteBuffer);
                    if (read > 0) {
                        byteBuffer.flip();
                        byte[] bytes = new byte[read];
                        byteBuffer.get(bytes);
                        String body = new String(bytes, StandardCharsets.UTF_8);
                        System.out.println("Now is :" + body);
                        this.stop = true;
                    } else if (read < 0) {
                        selectionKey.cancel();
                        socketChannel.close();
                    } else {
                        ; // 读取 0 字节
                    }
                }
            }
        }
    }


}
